package com.liuyu.common.framework.common.utils;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import com.liuyu.common.framework.common.util.IdUtils;
import com.liuyu.common.framework.lang.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @ClassName HttpDownUtils
 * @Author: liuyu
 * @Date: Created in 2021/7/8 14:23
 * @Version: 1
 * @Modified By:
 */
@Slf4j
public class HttpDownUtils {

    private static final String TYPE_ONE = "1";

    /**
     * 创建一个内存映射
     * @param key key
     * @param maxBodyLength 响应体字节上限
     * @return 内存映射
     * @throws IOException 文件创建失败异常
     */
    public static MappedByteBuffer createMappedByteBuffer(String key, int maxBodyLength) throws IOException {
        RandomAccessFile accessFile = new RandomAccessFile(File.createTempFile(key, "map"), "rw");
        FileChannel fileChannel = accessFile.getChannel();
        return fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, maxBodyLength);
    }


    /**
     * 给映射的内存赋值
     * @param value 值
     * @param buffer 映射的内存
     * @return buffer
     */
    public static MappedByteBuffer setValue(byte[] value, MappedByteBuffer buffer) {
        buffer.clear();
        buffer.put(value);
        buffer.flip();
        return buffer;
    }


    /**
     * 网上获取文件
     *
     * @param url 资源路径
     */
    public static boolean getInternetResByZeroCopy(String url, HttpServletResponse response, String contentType, String type, String fileName) {
        HttpResponse status = HttpRequest.get(url).timeout(10000).execute();
        if (status.isOk()) {
            try {
                byte[] bytes = status.bodyBytes();
                int size = bytes.length;
                log.info("文件下载成功:{}", size);
                MappedByteBuffer buffer = createMappedByteBuffer(IdUtils.snowflakeNextIdStr(), size);
                setValue(bytes, buffer);
                byte[] bytes1 = new byte[size];
                response.setContentType(contentType);
                for (int offset = 0; offset < size; offset++) {
                    byte b = buffer.get();
                    bytes1[offset] = b;
                }
                OutputStream outputStream = response.getOutputStream();
//        其中比较关键的是Content - Disposition是inline而不是attachment，这样提示浏览器来显示文档而不是下载
                if (TYPE_ONE.equals(type)) {
                    response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
                } else {
                    response.setHeader("Content-Disposition", "inline;fileName=" + fileName);
                }
                outputStream.write(bytes1);
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
                return false;
            }
        } else if (status.getStatus() == HttpStatus.HTTP_MOVED_TEMP) {
            log.info("文件下载进行跳转");
            //处理跳转
            String location = status.header("Location");
            return getInternetResByZeroCopy(location, response, contentType, type, fileName);
        } else {
            throw new BusinessException("文件下载失败:{},{}", status.getStatus(), status.body());
        }
        return true;
    }


    /**
     * 网上获取文件
     *
     * @param resurl 资源路径
     */
    public static boolean getInternetRes(String resurl, HttpServletResponse response) {
        URL url = null;
        HttpURLConnection con = null;
        InputStream in = null;
        OutputStream out = null;
        try {
            url = new URL(resurl);
            //建立http连接，得到连接对象
            con = (HttpURLConnection) url.openConnection();
            in = con.getInputStream();
            //转化为byte数组
            byte[] data1 = getByteData(in);
            System.out.println(data1.length);
            HttpResponse status = HttpRequest.get(resurl).execute();
            byte[] data = status.bodyBytes();
            System.out.println(data.length);
            out = response.getOutputStream();
            out.write(data);
            out.flush();

        } catch (MalformedURLException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (null != out) {
                    out.close();
                }
                if (null != in) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return true;
    }


    /**
     * 从输入流中获取字节数组
     *
     * @param in
     * @return
     * @throws IOException
     */
    private static byte[] getByteData(InputStream in) throws IOException {
        byte[] b = new byte[1024];
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int len = 0;
        while ((len = in.read(b)) != -1) {
            bos.write(b, 0, len);
        }
        if (null != bos) {
            bos.close();
        }
        return bos.toByteArray();
    }
}
